{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Playing with matrices\n",
    "(and if you get the subliminal message about abstractions, we'll be thrilled!)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Julia is a dynamic language.  You don't need type declarations, and can change variable types dynamically and interactively.\n",
    "\n",
    "For working with simple numbers, arrays, and strings, its syntax is *superficially* similar to Matlab, Python, and other popular languages.\n",
    "\n",
    "In order to execute the `In` cells, select the cell and press `Shift-Enter`, or press the `Play` button above. To run the entire notebook, navigate to the `Cell` menu and then `Run All`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# We tell beginners, you don't need types!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "typeof(1.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "typeof(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "S = \"Hello Julia Class\"\n",
    "typeof(S)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#  Exercise fix my spelling in the cell above\n",
    "S"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Now forget all that (for now): Julia is not so different from your favorite dynamic language"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "1 + 1  # shift + enter to run"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = rand(5, 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using LinearAlgebra # A LinearAlgebra standard package contains structured matrices\n",
    "A = SymTridiagonal(rand(6), rand(5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = rand(6)\n",
    "A \\ b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = fill(3.15, 5, 5) # Fill a 5x5 array with 3.15's"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Let's create some addition tables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First let's use a nested for loop to fill in a matrix that's initially zero:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = zeros(5, 5)\n",
    "\n",
    "for i in 1:5\n",
    "    for j in 1:5\n",
    "        A[i, j] = i+j  # Square brackets for indices.  Also: indices start at 1, not 0.\n",
    "    end\n",
    "end\n",
    "\n",
    "A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can abbreviate this using a double `for` loop:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in 1:5, j in 1:5\n",
    "   A[i, j] = i+j  # Square brackets for indices.  Also: indices start at 1, not 0.\n",
    "end\n",
    "\n",
    "A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Julia way would be to use a so-called **array comprehension**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "[i+j for i in 1:5, j in 1:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Equivalently,\n",
    "[i+j for i = 1:5, j = 1:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Explore**: What does the following do? "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "[i for i in (1:7).^2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# What happens when  we remove the dot syntax?\n",
    "[i for i in (1:7)^2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "[i^2 for i in 1:7]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Explore**: What does the following do? "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sort(unique(x^2 + y^2 for x in 1:5, y in 1:5))  # The inner parentheses define a **generator**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Suppose we want to see $n \\times n$ multiplication tables for $n=1,2,3,4,5$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for n in 1:5\n",
    "    display([i*j for i=1:n, j=1:n])\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `Interact.jl` is a Julia *package* for interacting with data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It's way more fun to **interact** with our data.\n",
    "We install the `Interact.jl` package as follows; this needs to be executed only once for any given Julia installation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# using Pkg; Pkg.add(\"Interact\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we load the package with the following `using` command, in each Julia session:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using Interact"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The package contains a `@manipulate` macro, that is wrapped around a `for` loop:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@manipulate for n in 1:1000\n",
    "    n\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@manipulate for n in 1:20\n",
    "    [i*j for i in 1:n, j in 1:n]\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We use a double `for` loop to get a double slider!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@manipulate for n in 3:10, i in 1:9\n",
    "   A = fill(0, n, n)\n",
    "   A[1:3, 1:3] .= i    # fill a sub-block\n",
    "A\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Julia is built around functions: all \"commands\" or \"operations\" in Julia are functions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# verbose form:\n",
    "function f(x)\n",
    "    x^2\n",
    "end\n",
    "\n",
    "# one-line form:\n",
    "f2(x) = x^2\n",
    "\n",
    "# anonymous form:\n",
    "f3 = x -> x^2;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Functions just work, as long as they make sense:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The square of a matrix is unambiguously defined\n",
    "f(rand(3, 3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# What the 'square of a vector' means is ambiguous\n",
    "f(rand(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# In the definition below, `a` and `power` are optional arguments to `f`, supplied with default values.\n",
    "function f(x, a=1, power=2)\n",
    "    a*x^power\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# `a` defaults to 1 and `power` to 2\n",
    "f(7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The first optional argument passed is assigned to the local variable `a`\n",
    "# `power` defaults to 2\n",
    "f(10, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f(10, 3, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's define a function to insert a block in a matrix:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "function insert_block(A, i, j, what=7)\n",
    "    B = A[:,:]        # B is a copy of A       \n",
    "    B[i:i+2, j:j+2] = fill(what, 3, 3)\n",
    "    \n",
    "    return B          # the `return` keyword is optional\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = fill(0, 9, 9)\n",
    "insert_block(A, 3, 5)  # this returns the new matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = fill(0, 9, 9)\n",
    "insert_block(A, 3, 5, 2)  # Use 2 instead of 7"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can move the block around:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = fill(0, 10, 10)\n",
    "n = size(A, 1)\n",
    "\n",
    "@manipulate for i in 1:n-2, j in 1:n-2\n",
    "    insert_block(A, i, j)\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Strings"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Julia can manipulate strings easily:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "S = \"Hello\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "replace(S, \"H\" => \"J\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string(S, \" \", S, \" \", \"Julia; a = \", a)  # build a string by concatenating things"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "More about strings: <a href=\"http://docs.julialang.org/en/stable/manual/strings/\"> Julia Doc on Strings </a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Functions in Julia try to be **generic**, i.e. to work with as many kinds of object as possible:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = fill(\"Julia\", 5, 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Julia allows us to display objects in different ways. For example, the following code displays a matrix of strings\n",
    "in the notebook using an HTML representation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "function Base.show(io::IO, ::MIME\"text/html\", M::Matrix{T}) where {T<:String}\n",
    "    max_length = maximum(length.(M))\n",
    "    dv=\"<div style='display:flex;flex-direction:row'>\"\n",
    "    print(io, dv*join([join(\"<div style='width:40px; text-align:center'>\".*M[i,:].*\"</div>\", \" \") for i in 1:size(M, 1)]\n",
    "            , \"</div>$dv\")*\"</div>\")\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Remember this ????\n",
    "A = fill(0, 10, 10)\n",
    "n = size(A, 1)\n",
    "\n",
    "@manipulate for i in 1:n-2, j in 1:n-2\n",
    "    insert_block(A, i,j)\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's use the **same code**, but now with strings:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = fill(\"Julia\", 10, 10)\n",
    "n = size(A, 1)\n",
    "\n",
    "@manipulate for i in 1:n-2, j in 1:n-2\n",
    "    insert_block(A, i,j, \"[FUN]\")\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@manipulate for i in 1:n-2, j in 1:n-2\n",
    "    insert_block(A, i, j, \"π\")\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@manipulate for i in 1:n-2, j in 1:n-2\n",
    "    insert_block(A, i, j, \"♡\")\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "airplane = \"✈\"\n",
    "alien = \"👽\"\n",
    "rand([airplane, alien], 5, 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = fill(airplane, 9, 9)\n",
    "n = size(A, 1)\n",
    "\n",
    "@manipulate for i in 1:n-2, j in 1:n-2\n",
    "    insert_block(A, i, j, alien)\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Colors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `Colors` package provides objects representing colours:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# using Pkg; Pkg.add(\"Colors\")\n",
    "using Colors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "distinguishable_colors(12)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@manipulate for n in 1:80\n",
    "    distinguishable_colors(n)\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "colors = distinguishable_colors(100)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Remember this ????\n",
    "A = fill(0, 10, 10)\n",
    "n = size(A, 1)\n",
    "\n",
    "@manipulate for i in 1:n-2, j in 1:n-2\n",
    "    insert_block(A, i, j)\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What happens if we use colors instead?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = fill(colors[1], 10, 10)\n",
    "n = size(A, 1)\n",
    "\n",
    "@manipulate for i in 1:n-2, j in 1:n-2\n",
    "    insert_block(A, i, j, colors[4])\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise: Create Tetris Pieces, have them fall from the top"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Julia 1.0.0",
   "language": "julia",
   "name": "julia-1.0"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "1.0.0"
  },
  "toc": {
   "colors": {
    "hover_highlight": "#DAA520",
    "running_highlight": "#FF0000",
    "selected_highlight": "#FFD700"
   },
   "moveMenuLeft": true,
   "nav_menu": {
    "height": "248px",
    "width": "252px"
   },
   "navigate_menu": true,
   "number_sections": true,
   "sideBar": true,
   "threshold": "2",
   "toc_cell": false,
   "toc_section_display": "block",
   "toc_window_display": false
  },
  "widgets": {
   "state": {
    "03e03820-87b0-457b-ab42-ded0426544fd": {
     "views": [
      {
       "cell_index": 69
      }
     ]
    },
    "112a7d1d-27a4-41ed-86dd-495c55c3cc41": {
     "views": [
      {
       "cell_index": 76
      }
     ]
    },
    "303254d1-f92c-4694-bec9-228877cbfeaa": {
     "views": [
      {
       "cell_index": 32
      }
     ]
    },
    "3ab85729-787a-45d8-93bc-18d160c42925": {
     "views": [
      {
       "cell_index": 67
      }
     ]
    },
    "59018bf0-5304-420a-954c-b60b6ade41bc": {
     "views": [
      {
       "cell_index": 35
      }
     ]
    },
    "6596be93-5ae6-44d8-9928-118f26925ca2": {
     "views": [
      {
       "cell_index": 66
      }
     ]
    },
    "6ddddb05-e17f-4527-b346-b03c7654a9bd": {
     "views": [
      {
       "cell_index": 50
      }
     ]
    },
    "73b7ac02-1931-45ea-bab0-a0661446f2c4": {
     "views": [
      {
       "cell_index": 78
      }
     ]
    },
    "7fbfcf1d-2446-46b0-8c48-137bd1b04e59": {
     "views": [
      {
       "cell_index": 50
      }
     ]
    },
    "82e70dac-395e-4e4b-99d8-7c86157baef8": {
     "views": [
      {
       "cell_index": 67
      }
     ]
    },
    "9c1f13ea-b532-45c7-b638-4f2e0753e701": {
     "views": [
      {
       "cell_index": 33
      }
     ]
    },
    "a01da64b-6f5f-4ec4-bfb6-0dd4b5608910": {
     "views": [
      {
       "cell_index": 63
      }
     ]
    },
    "a0cab882-0559-4d6a-a78f-f1c28aafece6": {
     "views": [
      {
       "cell_index": 35
      }
     ]
    },
    "a81871a0-14a4-41b1-a6c5-4fcdccafa1ab": {
     "views": [
      {
       "cell_index": 69
      }
     ]
    },
    "b2248808-aeeb-40c7-a647-29ff9e394260": {
     "views": [
      {
       "cell_index": 65
      }
     ]
    },
    "b59a0470-d356-4c66-9c43-a590a92e4925": {
     "views": [
      {
       "cell_index": 66
      }
     ]
    },
    "b8661b37-c86d-484e-8225-0965da985371": {
     "views": [
      {
       "cell_index": 65
      }
     ]
    },
    "ba049dd3-9042-4cc9-acce-f07f08746316": {
     "views": [
      {
       "cell_index": 76
      }
     ]
    },
    "cbf99c6a-4771-4b80-a2bf-22d90cd5fb84": {
     "views": [
      {
       "cell_index": 74
      }
     ]
    },
    "e1aeaa28-549c-4032-b84e-ef9b2ba7a74e": {
     "views": [
      {
       "cell_index": 63
      }
     ]
    },
    "e1f5a7f1-25fe-4147-9ab0-c58a324d613a": {
     "views": [
      {
       "cell_index": 78
      }
     ]
    }
   },
   "version": "1.2.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
